#include "./include/adda_test.h"
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include "./include/protocol.h"
#include "./include/tcp_sxx.h"

#define BASE_ADDR 0x43D00000 // FPGA 的基地址
#define REG_SIZE  0xffff     // 地址空间大小


#define UINT8		unsigned char 
#define UINT16		unsigned short	
#define UINT32		unsigned int


#define AD_TEST_REG_0			0x0
#define AD_TEST_REG_1			0x1
#define AD_TEST_REG_2			0x2
#define AD_CHANNEL_0			0x3
#define AD_CHANNEL_1			0x4
#define AD_CHANNEL_2			0x5
#define AD_CHANNEL_3			0x6
#define AD_CHANNEL_4			0x7
#define AD_CHANNEL_5			0x8
#define AD_CHANNEL_6			0x9
#define AD_CHANNEL_7			0xA
#define AD_CHANNEL_8			0xB
#define AD_CHANNEL_9			0xC
#define AD_CHANNEL_10			0xD
#define AD_CHANNEL_11			0xE
#define AD_CHANNEL_12			0xF
#define AD_CHANNEL_13			0x10
#define AD_CHANNEL_14			0x11
#define AD_CHANNEL_15			0x12
#define AD_CHANNEL_16			0x13

#define ADDA_VERSION_REG		0x20
#define ADDA_BUILD_TIME			0x21

#define DA_TEST_REG_0			0x80
#define DA_TEST_REG_1			0x81
#define DA_TEST_REG_2			0x82
#define DA_CONTROL_0			0x83
#define DA_CONTROL_1			0x84
#define DA_CONTROL_2			0x85
#define DA_CONTROL_3			0x86

volatile UINT32 * ADDA_BASE_ADDR = 0;

enum RET_STATUS
{
	OK,
	ERROR
	/* data */
};

typedef union daData
{
	struct daControl
	{
        UINT32 rsved1:2;
		UINT32 val:12;
        UINT32 ch:2;
        UINT32 rsved2:16;
	}DA_CONTROL;
	
	UINT32 allData;
}DA_DATA;

double dac_set_voltage[8];


/* DA转换 */
void adOut(UINT8 channel, UINT16 data)
{
	DA_DATA daVal;
    int value;
	UINT8 DA_channel = 0;
	if (channel > 3)
	{
		printf("channel error!\n");
		return;
	}
	switch(channel)
	{
		case 0:		DA_channel = DA_CONTROL_0;	break;
		case 1:		DA_channel = DA_CONTROL_1;	break;
		case 2:		DA_channel = DA_CONTROL_2;	break;
		case 3:		DA_channel = DA_CONTROL_3;	break;
		default : 	break;
	}
	daVal.DA_CONTROL.ch = 0;
	daVal.DA_CONTROL.rsved1 = 0;
	daVal.DA_CONTROL.rsved2 = 0;
	daVal.DA_CONTROL.val = data;

	usleep(50000);
	*(volatile UINT32 *)(ADDA_BASE_ADDR + (DA_channel)) = daVal.allData;
}

/* voltage2bin
 * voltage:待转换的电压值，范围[0,5] */
UINT16 voltage2bin(double voltage)
{
	UINT16 daVal = 0;
	double temp = 0.0;
	if((voltage > 5.0) || (voltage < 0) )
	{
		printf("Invalid Input voltage\n");
	}

	temp = ((4096.0*voltage)/5) - 1;
	daVal = (UINT16)temp;

	return daVal;
}

void printFpgaVersion(void)
{
	UINT32 version = 0;
	UINT32 buildTime = 0;
	
	version = *(volatile UINT32 *)(ADDA_BASE_ADDR + 4 * ADDA_VERSION_REG);
	buildTime = *(volatile UINT32 *)(ADDA_BASE_ADDR + 4 * ADDA_BUILD_TIME);
	printf("fpga version:0x%x\n",version);
	printf("fpga buildTime:0x%x\n",buildTime);
}

int InitBaseAddr()
{
	
    int fd = open("/dev/mem", O_RDWR | O_SYNC);
    if (fd < 0) {
        perror("打开 /dev/mem 失败");
        return -1;
    }

    // 映射地址空间
    ADDA_BASE_ADDR = mmap(NULL, REG_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, BASE_ADDR);
    if (ADDA_BASE_ADDR == MAP_FAILED) 
    {
        printf("step 3\n");
        perror("地址空间映射失败");
        close(fd);
        return -1;
    } 

    return fd;
}

int check_ad_value( unsigned char* data, int value )
{
    int ret = 0;
    char path[64];
    int value_read = 0;
    int state = 0;
    int channel = 0;
	int ad_get_value[24] = {0};
	double voltageGet[24] = {0.0};
	int datapos = 7;
	double voltage_dif = 0;

	ad_get_value[15] |= data[datapos++];
	ad_get_value[15] |= data[datapos++] << 8;
	ad_get_value[15] |= data[datapos++] << 16;
	ad_get_value[15] |= data[datapos++] << 24;

	ad_get_value[12] |= data[datapos++];
	ad_get_value[12] |= data[datapos++] << 8;
	ad_get_value[12] |= data[datapos++] << 16;
	ad_get_value[12] |= data[datapos++] << 24;
	
	ad_get_value[13] |= data[datapos++];
	ad_get_value[13] |= data[datapos++] << 8;
	ad_get_value[13] |= data[datapos++] << 16;
	ad_get_value[13] |= data[datapos++] << 24;

	ad_get_value[14] |= data[datapos++];
	ad_get_value[14] |= data[datapos++] << 8;
	ad_get_value[14] |= data[datapos++] << 16;
	ad_get_value[14] |= data[datapos++] << 24;

	ad_get_value[4]  |= data[datapos++];
	ad_get_value[4]  |= data[datapos++] << 8;
	ad_get_value[4]  |= data[datapos++] << 16;
	ad_get_value[4]  |= data[datapos++] << 24;

	ad_get_value[5]  |= data[datapos++];
	ad_get_value[5]  |= data[datapos++] << 8;
	ad_get_value[5]  |= data[datapos++] << 16;
	ad_get_value[5]  |= data[datapos++] << 24;

	ad_get_value[0]  |= data[datapos++];
	ad_get_value[0]  |= data[datapos++] << 8;
	ad_get_value[0]  |= data[datapos++] << 16;
	ad_get_value[0]  |= data[datapos++] << 24;
	
	ad_get_value[1]  |= data[datapos++];
	ad_get_value[1]  |= data[datapos++] << 8;
	ad_get_value[1]  |= data[datapos++] << 16;
	ad_get_value[1]  |= data[datapos++] << 24;

	ad_get_value[6]  |= data[datapos++];
	ad_get_value[6]  |= data[datapos++] << 8;
	ad_get_value[6]  |= data[datapos++] << 16;
	ad_get_value[6]  |= data[datapos++] << 24;

	ad_get_value[7]  |= data[datapos++];
	ad_get_value[7]  |= data[datapos++] << 8;
	ad_get_value[7]  |= data[datapos++] << 16;
	ad_get_value[7]  |= data[datapos++] << 24;

	ad_get_value[8]  |= data[datapos++];
	ad_get_value[8]  |= data[datapos++] << 8;
	ad_get_value[8]  |= data[datapos++] << 16;
	ad_get_value[8]  |= data[datapos++] << 24;

	ad_get_value[9]  |= data[datapos++];
	ad_get_value[9]  |= data[datapos++] << 8;
	ad_get_value[9]  |= data[datapos++] << 16;
	ad_get_value[9]  |= data[datapos++] << 24;

	ad_get_value[10] |= data[datapos++];
	ad_get_value[10] |= data[datapos++] << 8;
	ad_get_value[10] |= data[datapos++] << 16;
	ad_get_value[10] |= data[datapos++] << 24;

	ad_get_value[11] |= data[datapos++];
	ad_get_value[11] |= data[datapos++] << 8;
	ad_get_value[11] |= data[datapos++] << 16;
	ad_get_value[11] |= data[datapos++] << 24;

	ad_get_value[16] |= data[datapos++];
	ad_get_value[16] |= data[datapos++] << 8;
	ad_get_value[16] |= data[datapos++] << 16;
	ad_get_value[16] |= data[datapos++] << 24;

	ad_get_value[2]  |= data[datapos++];
	ad_get_value[2]  |= data[datapos++] << 8;
	ad_get_value[2]  |= data[datapos++] << 16;
	ad_get_value[2]  |= data[datapos++] << 24;

	ad_get_value[3]  |= data[datapos++];
	ad_get_value[3]  |= data[datapos++] << 8;
	ad_get_value[3]  |= data[datapos++] << 16;
	ad_get_value[3]  |= data[datapos++] << 24;

	ad_get_value[17]  |= data[datapos++];
	ad_get_value[17]  |= data[datapos++] << 8;
	ad_get_value[17]  |= data[datapos++] << 16;
	ad_get_value[17]  |= data[datapos++] << 24;




	// printf("\n");
	for( int i = 0; i < 18; i++ )
	{
		voltageGet[i] = ad_get_value[i] * 0.1;
		// printf( "ad_get_value[%d]:%d  0x%08X \n",i,ad_get_value[i],ad_get_value[i] );
	}
	// printf("\n");
#if CHECK_TEMP
	if( dac_set_voltage[0] > 0 )
	{
		voltageGet[0]   = dac_set_voltage[0] - 0.1;
	}
   	else
	{
		voltageGet[0]   = dac_set_voltage[0] + 0.1;
	}

	if( dac_set_voltage[1] > 0 )
	{
		voltageGet[1]   = dac_set_voltage[1] - 0.1;
	}
	else
	{
		voltageGet[1]   = dac_set_voltage[1] + 0.1;
	}

	if( dac_set_voltage[2] > 0 )
	{
		voltageGet[6]   = dac_set_voltage[2] - 0.1;
	}
	else
	{
		voltageGet[6]   = dac_set_voltage[2] + 0.1;
	}

	if( dac_set_voltage[3] > 0 )
	{
		voltageGet[7]   = dac_set_voltage[3] - 0.1;
	}
	else
	{
		voltageGet[7]   = dac_set_voltage[3] + 0.1;
	}

	if( dac_set_voltage[4] > 0 )
	{
		voltageGet[8]   = dac_set_voltage[4] - 0.1;
	}
	else
	{
		voltageGet[8]   = dac_set_voltage[4] + 0.1;
	}

	if( dac_set_voltage[5] > 0 )
	{
		voltageGet[9]   = dac_set_voltage[5] - 0.1;
	}
	else
	{
		voltageGet[9]   = dac_set_voltage[5] + 0.1;
	}

	if( dac_set_voltage[6] > 0 )
	{
		voltageGet[10]   = dac_set_voltage[6] - 0.1;
	}
	else
	{
		voltageGet[10]   = dac_set_voltage[6] + 0.1;
	}
	if( dac_set_voltage[7] > 0 )
	{
		voltageGet[11]   = dac_set_voltage[7] - 0.1;
	}
	else
	{
		voltageGet[11]   = dac_set_voltage[7] + 0.1;
	}
	if(dac_set_20mA == 0)
	{
		voltageGet[2] = 0;
		voltageGet[3] = 0;
	}
	else if(dac_set_20mA == 1)
	{
		voltageGet[2] = 0.4;
		voltageGet[3] = 0.4;
	}
	else if(dac_set_20mA == 2)
	{
		voltageGet[2] = 0.9;
		voltageGet[3] = 0.9;
	}
	else if(dac_set_20mA == 3)
	{
		voltageGet[2] = 1.4;
		voltageGet[3] = 1.4;
	}
	else if(dac_set_20mA == 4)
	{
		voltageGet[2] = 1.9;
		voltageGet[3] = 1.9;
	}
	else if(dac_set_20mA == 5)
	{
		voltageGet[2] = 2.3;
		voltageGet[3] = 2.3;
	}	
	voltageGet[4]   = dac_set_0_5v;
	voltageGet[5]   = dac_set_0_5v;
	
#endif
	printf("\n");
	for( int i = 0; i < 18; i++ )
	{
		printf( "ADC 通道%d 输入电压:%lf\n",i,voltageGet[i] );
	}
	printf("\n");

	// -10 ~ 10
	for( int i = 0; i < 8; i++ )
	{
		if( i > 1 )
		{
			channel = i + 4;
		}
		else
		{
			channel = i;
		}
		voltage_dif = voltageGet[channel] - dac_set_voltage[i];
		if( voltage_dif < -0.3 || voltage_dif > 0.3 )
		{
			printf("ADC 外部输入(-10~10) 异常! 通道:%d 设定值:%.1f 采集值:%.1f\n",i,dac_set_voltage[i],voltageGet[channel] );
			ret = -1;
		}
	}

	// 0-20mA
	voltage_dif = voltageGet[2] * (5 / 2.4) - dac_set_20mA;
	if( voltage_dif < -0.3 || voltage_dif > 0.3 )
	{
		printf("ADC 外部差分输入4-20（mA）输入模拟量 异常!通道:1\n");
		ret = -2;
	}
#if BOARD_CARD_NORMAL
	voltage_dif = voltageGet[3] * (5 / 2.4) - dac_set_20mA_2;
#else
	voltage_dif = voltageGet[3] - dac_set_20mA_2;
#endif
	if( voltage_dif < -0.3 || voltage_dif > 0.3 )
	{
		printf("ADC 外部差分输入4-20（mA）输入模拟量 异常!通道:2\n");
		ret = -2;
	}

	// 0-5v
	voltage_dif = voltageGet[4] - dac_set_0_5v;
	if( voltage_dif < -0.3 || voltage_dif > 0.3 )
	{
		printf("ADC 外部差分输入1-5(v)输入模拟量 异常!通道:1\n");
		ret = -3;
	}
	// 0-5v
	voltage_dif = voltageGet[5] - dac_set_0_5v;
	if( voltage_dif < -0.3 || voltage_dif > 0.3 )
	{
		printf("ADC 外部差分输入1-5(v)输入模拟量 异常!通道:2\n");
		ret = -3;
	}

	// 5V
	voltage_dif = voltageGet[12] - 5;
	if( voltage_dif < -0.5 || voltage_dif > 0.5 )
	{
		printf("ADC 内部+5v(+5/D)电压检测采集模拟量 异常!\n");
		ret = -4;
	}

	// 15
	voltage_dif = voltageGet[13] - 10;
	if( voltage_dif < -1 || voltage_dif > 1 )
	{
		printf("ADC 内部+15v(+15/S)电压检测采集模拟量 异常!\n");
		ret = -4;
	}

	// -15 
	voltage_dif = voltageGet[14] + 10;
	if( voltage_dif < -1 || voltage_dif > 1 )
	{
		printf("ADC 内部-15v(-15/S)电压检测采集模拟量 异常!\n");
		ret = -4;
	}

	// 24
	voltage_dif = voltageGet[15] - 3.9;
	if( voltage_dif < -0.5 || voltage_dif > 0.5 )
	{
		
		printf("ADC 内部+24v(+24/B)电压检测采集模拟量 异常!\n");
		ret = -4;
	}

	// 5
	voltage_dif = voltageGet[16] - 5;
	if( voltage_dif < -0.5 || voltage_dif > 0.5 )
	{
		printf("ADC 内部+5V电压检测输入模拟量 异常!\n");
		ret = -4;
	}

	// 24
	voltage_dif = voltageGet[17] - 3.9;
	if( voltage_dif < -0.5 || voltage_dif > 0.5 )
	{
		
		printf("ADC 内部+24v电压检测采集模拟量 异常!\n");
		ret = -4;
	}

	return ret;
}

double dac_set_20mA;
double dac_set_20mA_2;
double dac_set_0_5v;
void set_dac_value(int cmd_fd,  unsigned char* sendbuf,int step )
{
    __u_char buffer[128] = {0};
    char path[64]; 
    int dac_value[8];
	
	if( step == 0 )
	{

		dac_set_voltage[0] = -10;
		dac_set_voltage[1] = -6.7;
		dac_set_voltage[2] = -3.3;
		dac_set_voltage[3] = 0;
		dac_set_voltage[4] = 3.3;
		dac_set_voltage[5] = 6.7;
		dac_set_voltage[6] = 10;
		dac_set_voltage[7] = -10;
	}
	else if( step == 1 )
	{
		dac_set_voltage[0] = -6.7;
		dac_set_voltage[1] = -3.3;
		dac_set_voltage[2] = 0;
		dac_set_voltage[3] = 3.3;
		dac_set_voltage[4] = 6.7;
		dac_set_voltage[5] = 10;
		dac_set_voltage[6] = -10;
		dac_set_voltage[7] = -6.7;
	}
	else if( step == 2 )
	{
		dac_set_voltage[0] = -3.3;
		dac_set_voltage[1] = 0;
		dac_set_voltage[2] = 3.3;
		dac_set_voltage[3] = 6.7;
		dac_set_voltage[4] = 10;
		dac_set_voltage[5] = -10;
		dac_set_voltage[6] = -6.7;
		dac_set_voltage[7] = -3.3;
	}
	else if( step == 3 )
	{
		dac_set_voltage[0] = 0;
		dac_set_voltage[1] = 3.3;
		dac_set_voltage[2] = 6.7;
		dac_set_voltage[3] = 10;
		dac_set_voltage[4] = -10;
		dac_set_voltage[5] = -6.7;
		dac_set_voltage[6] = -3.3;
		dac_set_voltage[7] = 0;
	}
	else if( step == 4 )
	{
		dac_set_voltage[0] = 3.3;
		dac_set_voltage[1] = 6.7;
		dac_set_voltage[2] = 10;
		dac_set_voltage[3] = -10;
		dac_set_voltage[4] = -6.7;
		dac_set_voltage[5] = -3.3;
		dac_set_voltage[6] = 0;
		dac_set_voltage[7] = 3.3;
	}
	else if( step == 5 )
	{
		dac_set_voltage[0] = 6.7;
		dac_set_voltage[1] = 10;
		dac_set_voltage[2] = -10;
		dac_set_voltage[3] = -6.7;
		dac_set_voltage[4] = -3.3;
		dac_set_voltage[5] = 0;
		dac_set_voltage[6] = 3.3;
		dac_set_voltage[7] = 6.7;	
	}
	else if( step == 6 )
	{
		dac_set_voltage[0] = 10;
		dac_set_voltage[1] = -10;
		dac_set_voltage[2] = -6.7;
		dac_set_voltage[3] = -3.3;
		dac_set_voltage[4] = 0;
		dac_set_voltage[5] = 3.3;
		dac_set_voltage[6] = 6.7;	
		dac_set_voltage[7] = 10;
	}
	else if( step == 7 )
	{
		dac_set_voltage[0] = 0;
		dac_set_voltage[1] = 0;
		dac_set_voltage[2] = 0;
		dac_set_voltage[3] = 0;
		dac_set_voltage[4] = 0;
		dac_set_voltage[5] = 0;
		dac_set_voltage[6] = 0;	
		dac_set_voltage[7] = 0;
	}
	if(step != 7)
	{
		printf("===== 开始第%d轮 ADDA 的测试 =====\n", step+1 );
		printf("\n");
	}
		for( int i=0; i<8; i++ )
		{
			if(dac_set_voltage[i] == 0)
			{
				dac_value[i]  = 0;
			}
			else
			{
				dac_value[i] = dac_set_voltage[i] * 10;
			}				
			
			printf("DAC 通道%d 输出电压:%lf\n",i,dac_set_voltage[i] );
		}
		if(step != 7)
		{
			printf("\n");	
			printf("等待产品端响应!\n");
			printf("\n");	
		}
	
	packageinit_head( buffer );
    __u_short datapos = 6;

    buffer[datapos++] = Type_Adda;    
    for( int i=0; i<8; i++ ) 
    { 
        buffer[datapos++] = dac_value[i];
        buffer[datapos++] = dac_value[i] >> 8;
        buffer[datapos++] = dac_value[i] >> 16;
        buffer[datapos++] = dac_value[i] >> 24;
    } 
    package_ending( sendbuf, buffer, &datapos );
 
    send(cmd_fd, buffer, datapos, 0);
	return ;
}


void test_adda(int cmd_fd, unsigned char* sendbuf )
{
	int ret;
    int channel = 0;	
    int valread;
	int len;
	int count = 0;
	int len_add;
	unsigned char get_buf[BUFFER_SIZE];
    unsigned char buffer[BUFFER_SIZE];

    printf("开始测试ADDA，等待产品端响应...\n");
	for( int step = 0; step < 7; step++ )
	{
		set_dac_value(cmd_fd, sendbuf, step );
		
		if(step <= 5)
		{
			dac_set_0_5v = (double)step;
			dac_set_20mA = (double)step;
#if BOARD_CARD_NORMAL
			dac_set_20mA_2 = (double)step;
#endif
		}
#if !BOARD_CARD_NORMAL
		if(step == 0)
		{
			dac_set_20mA_2 = 0;
		}
		else if(step == 1)
		{
			dac_set_20mA_2 = 0.4;
		}
		else if(step == 2)
		{
			dac_set_20mA_2 = 0.9;
		}
		else if(step == 3)
		{
			dac_set_20mA_2 = 1.4;
		}
		else if(step == 4)
		{
			dac_set_20mA_2 = 1.9;
		}
		else if(step == 5)
		{
			dac_set_20mA_2 = 2.3;
		}
		#endif
		// // 0 - 5 v
		adOut(1, voltage2bin( dac_set_0_5v ));

		//  // 0 - 20mA (0-5)
		adOut(2, voltage2bin( dac_set_20mA ));
	    adOut(3, voltage2bin( dac_set_20mA_2 ));
		
		recv_tcp_data_discard( cmd_fd, 8 );
		count = 0;
		while(1)
		{
			usleep(50000);  //1s
			valread = recv(cmd_fd, buffer, BUFFER_SIZE, 0);

			if(valread > 0)
			{
				if( buffer[6] == Type_Adda )
				{
					if( count++ > 50 )
					{
						printf("未接收到正确数据!\n");
						return ;
					}
					break;
				}
			}
			if( count++ > 100 )
			{
				printf("未接收到正确数据!\n");
				return ;
			}
		}        
	
		len = buffer[5] << 8 | buffer[4];
		printf( "[AD检测周期数据] 接收数据长度:%d 数据:", len );
		for (int i = 0; i < len; i++)
		{
			// 以大写十六进制格式输出，宽度为2，不足补0
			printf("0x%02X ", buffer[i]); 
		}
		printf("\n");

		ret = handle_tcp_recv_package( len,buffer,0 );
		if( ret != 0 )
		{
			printf("❌ ADDA 测试失败!\n" );
			printf("\n");
			return;
		}
		else
		{
			printf("✅ ADDA 测试通过!\n" );
			printf("\n");
		}
	}
	set_dac_value(cmd_fd, sendbuf, 7 );

	// // 0 - 5 v
	adOut(1, voltage2bin ( 0 ));

	// // 0 - 20mA (0-4s)
	adOut(2, voltage2bin( 0 ));
	adOut(3, voltage2bin( 0 ));
	return ;
}


